/**
 * 
 */
package jvs.peer.io;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;

/**
 * @author qiangli
 *
 */
public class PooledSocket extends Socket {

	public boolean closed;
	public boolean connected;
	public boolean bound;
	
	private SocketChannel socketChannel;
	private InputStream inputStream;
	private OutputStream outputStream;
	private boolean inputShutdown;
	private boolean outputShutdown;

	public PooledSocket(String host, int port) throws UnknownHostException,
			IOException {
		super(host, port);
		this.closed = false;
		this.connected = true;
	}

	@Override
	public synchronized void close() throws IOException {
		this.closed = true;
		
		flush(inputStream);
		flush(outputStream);
	}

	@Override
	public boolean isClosed() {
		return closed;
	}

	@Override
	public boolean isConnected() {
		return connected;
	}

	
	@Override
	public void bind(SocketAddress bindpoint) throws IOException {
		if (!bound) {
			super.bind(bindpoint);
		}
		bound = true;
	}

	@Override
	public void connect(SocketAddress endpoint, int timeout)
			throws IOException {
		if (!connected) {
			super.connect(endpoint, timeout);
		}
	}

	@Override
	public void connect(SocketAddress endpoint) throws IOException {
		if (!connected) {
			super.connect(endpoint);
		}
	}

	@Override
	public SocketChannel getChannel() {
		if (socketChannel == null) {
			try {
				socketChannel = super.getChannel();
			} catch (Exception e) {
				closed = true;
				connected = false;
			}
		}
		return socketChannel;
	}

	@Override
	public InputStream getInputStream() throws IOException {
		if (inputStream == null) {
			try {
				inputStream = super.getInputStream();
			} catch (Exception e) {
				closed = true;
				connected = false;
			}
		}
		return inputStream;
	}

	@Override
	public OutputStream getOutputStream() throws IOException {
		if (outputStream == null) {
			try {
				outputStream = super.getOutputStream();
			} catch (Exception e) {
				closed = true;
				connected = false;
			}
		}
		return outputStream;
	}

	@Override
	public boolean isInputShutdown() {
		return inputShutdown;
	}

	@Override
	public boolean isOutputShutdown() {
		return outputShutdown;
	}

	@Override
	public void shutdownInput() throws IOException {
		inputShutdown = true;
		flush(inputStream);
	}

	private void flush(Closeable c) {
		try {
			c.close();
		} catch (Exception e) {
			closed = true;
			connected = false;
		}
	}

	@Override
	public void shutdownOutput() throws IOException {
		outputShutdown = true;
		flush(outputStream);
	}

	public void destroy() {
		
		try {
			super.close();
		} catch (Exception e) {
			
		}
		this.closed = true;
		this.connected = false;
	}
}
